from chernc.textdiff.line_matcher import show_result


def example_1():
    lhs = """
// CHERNC_MARK: /data/wangjun/github/Chern-C/examples/bubblesort/bubblesort.c:3
fn swap(left: &mut i32, right: &mut i32) {
    let temp = *left;
    *left = *right;
    *right = temp;
}
// CHERNC_END_MARK: /data/wangjun/github/Chern-C/examples/bubblesort/bubblesort.c:3

// CHERNC_MARK: /data/wangjun/github/Chern-C/examples/bubblesort/bubblesort.c:10
fn bubble_sort(arry: &mut [i32], length: usize) {
    for i in 0..length-1 {
        for j in 0..length-i-1 {
            if arry[j] > arry[j+1] { // changed to use '>' for bubble sort
                let (left, right) = arry.split_at_mut(j + 1); // split the array into two parts
                swap(&mut left[j], &mut right[0]); // swap the elements
            }
        }
    }
}
// CHERNC_END_MARK: /data/wangjun/github/Chern-C/examples/bubblesort/bubblesort.c:10

// CHERNC_MARK: /data/wangjun/github/Chern-C/examples/bubblesort/bubblesort.c:25
fn main() {
    let mut input_array = [12, 43, 9, 13, 67, 98, 101, 89, 3, 35];
    println!("bubble sort the array");

    bubble_sort(&mut input_array, 10);

    // print the array
    print_array(&input_array, 10);
}
// CHERNC_END_MARK: /data/wangjun/github/Chern-C/examples/bubblesort/bubblesort.c:25
"""
    rhs = """
fn main() {
    let mut input_array = [12, 43, 9, 13, 67, 98, 101, 89, 3, 35];
    println!("bubble sort the array");

    bubble_sort(&mut input_array);
    print_array(&input_array, 10);
}
"""
    a_lines = [line.rstrip() for line in lhs.splitlines()]
    b_lines = [line.rstrip() for line in rhs.splitlines()]
    show_result(b_lines, a_lines, 0, 8)


def example_2():
    lhs = """
// CHERNC_MARK: /data/wangjun/github/Chern-C/examples/bubblesort/bubblesort.c:3
fn swap(left: &mut i32, right: &mut i32) {
    let temp = *left;
    *left = *right;
    *right = temp;
}
// CHERNC_END_MARK: /data/wangjun/github/Chern-C/examples/bubblesort/bubblesort.c:3

// CHERNC_MARK: /data/wangjun/github/Chern-C/examples/bubblesort/bubblesort.c:10
fn bubble_sort(arry: &mut [i32], length: usize) {
    for i in 0..length-1 {
        for j in 0..length-i-1 {
            if arry[j] > arry[j+1] { // changed to use '>' for bubble sort
                let (left, right) = arry.split_at_mut(j + 1); // split the array into two parts
                swap(&mut left[j], &mut right[0]); // swap the elements
            }
        }
    }
}
// CHERNC_END_MARK: /data/wangjun/github/Chern-C/examples/bubblesort/bubblesort.c:10

// CHERNC_MARK: /data/wangjun/github/Chern-C/examples/bubblesort/bubblesort.c:25
fn main() {
    let mut input_array = [12, 43, 9, 13, 67, 98, 101, 89, 3, 35];
    println!("bubble sort the array");

    bubble_sort(&mut input_array, 10);

    // print the array
    print_array(&input_array, 10);
}
// CHERNC_END_MARK: /data/wangjun/github/Chern-C/examples/bubblesort/bubblesort.c:25
"""
    rhs = """

// CHERNC_MARK: /data/wangjun/github/Chern-C/examples/bubblesort/bubblesort.c:10
fn bubble_sort(arry: &mut [i32], length: usize) {
    for i in 0..length-1 {
        for j in 0..length-i-1 {
            if arry[j] > arry[j+1] { // changed to use '>' for bubble sort
                let (left, right) = arry.split_at_mut(j + 1); // split the array into two parts
                swap(&mut left[j], &mut right[0]); // swap the elements
            }
        }
    }
}
// CHERNC_END_MARK: /data/wangjun/github/Chern-C/examples/bubblesort/bubblesort.c:10

// CHERNC_MARK: /data/wangjun/github/Chern-C/examples/bubblesort/bubblesort.c:25
fn main() {
    let mut input_array = [12, 43, 9, 13, 67, 98, 101, 89, 3, 35];
    println!("bubble sort the array");

    bubble_sort(&mut input_array, 10);

    // print the array
    print_array(&input_array, 10);
}
// CHERNC_END_MARK: /data/wangjun/github/Chern-C/examples/bubblesort/bubblesort.c:25

// CHERNC_MARK: /data/wangjun/github/Chern-C/examples/bubblesort/bubblesort.c:3
fn swap(left: &mut i32, right: &mut i32) {
    let temp = *left;
    *left = *right;
}
// CHERNC_END_MARK: /data/wangjun/github/Chern-C/examples/bubblesort/bubblesort.c:3

"""
    a_lines = [line.rstrip() for line in lhs.splitlines()]
    b_lines = [line.rstrip() for line in rhs.splitlines()]
    show_result(a_lines, b_lines, 1, 7)


def example_3():
    lhs = """
// CHERNC_MARK: /data/wangjun/github/Chern-C/examples/bubblesort/bubblesort.c:3
fn swap(left: &mut i32, right: &mut i32) {
    let temp = *left;
    *left = *right;
    *right = temp;
}
// CHERNC_END_MARK: /data/wangjun/github/Chern-C/examples/bubblesort/bubblesort.c:3

// CHERNC_MARK: /data/wangjun/github/Chern-C/examples/bubblesort/bubblesort.c:10
fn bubble_sort(arry: &mut [i32], length: usize) {
    for i in 0..length-1 {
        for j in 0..length-i-1 {
            if arry[j] > arry[j+1] { // changed to use '>' for bubble sort
                let (left, right) = arry.split_at_mut(j + 1); // split the array into two parts
                swap(&mut left[j], &mut right[0]); // swap the elements
            }
        }
    }
}
// CHERNC_END_MARK: /data/wangjun/github/Chern-C/examples/bubblesort/bubblesort.c:10

// CHERNC_MARK: /data/wangjun/github/Chern-C/examples/bubblesort/bubblesort.c:25
fn main() {
    let mut input_array = [12, 43, 9, 13, 67, 98, 101, 89, 3, 35];
    println!("bubble sort the array");

    bubble_sort(&mut input_array, 10);

    // print the array
    print_array(&input_array, 10);
}
// CHERNC_END_MARK: /data/wangjun/github/Chern-C/examples/bubblesort/bubblesort.c:25
"""
    rhs = """
fn main() {
    let mut input_array = [12, 43, 9, 13, 67, 98, 101, 89, 3, 35];
    println!("Original array: {:?}", input_array);
    println!("Bubble sort the array");

    bubble_sort(&mut input_array);

    // Print the sorted array
    println!("Sorted array: {:?}", input_array);
}

fn bubble_sort(arry: &mut [i32]) {
    let length = arry.len();
    for i in 0..length {
        for j in 0..length - i - 1 {
            if arry[j] > arry[j + 1] {
                arry.swap(j, j + 1);
            }
        }
    }
}

fn swap_new(left: &mut i32, right: &mut i32) {
    *left = std::mem::replace(right, *left);
}
"""
    a_lines = [line.rstrip() for line in lhs.splitlines()]
    b_lines = [line.rstrip() for line in rhs.splitlines()]
    show_result(a_lines, b_lines, 1, 7)

def example_4():
    lhs = """
// CHERNC_MARK: /data/wangjun/github/Chern-C/examples/c4/c4.c:47
fn next() {
  let mut pp: *const u8;

  while unsafe { *p } != 0 {
    tk = unsafe { *p };
    p = unsafe { p.add(1) };
    if tk == b'\n' {
      if src != 0 {
        println!("{}: {}{}{}", line, unsafe { std::ffi::CStr::from_ptr(lp as *const i8).to_string_lossy() }, unsafe { std::ffi::CStr::from_ptr(p as *const i8).to_string_lossy() }, unsafe { std::ffi::CStr::from_ptr(lp as *const i8).to_string_lossy() });
        lp = p;
        while le < e {
          println!("{:8.4}", unsafe { std::ffi::CStr::from_ptr(&["LEA", "IMM", "JMP", "JSR", "BZ", "BNZ", "ENT", "ADJ", "LEV", "LI", "LC", "SI", "SC", "PSH", "OR", "XOR", "AND", "EQ", "NE", "LT", "GT", "LE", "GE", "SHL", "SHR", "ADD", "SUB", "MUL", "DIV", "MOD", "OPEN", "READ", "CLOS", "PRTF", "MALC", "MSET", "MCMP", "EXIT"][*le as usize * 5]).to_string_lossy() });
          if *le <= ADJ { println!(" {}", *le); } else { println!(); }
        }
      }
      line += 1;
    } else if tk == b'#' {
      while unsafe { *p } != 0 && unsafe { *p } != b'\n' { p = unsafe { p.add(1) }; }
    } else if (tk >= b'a' && tk <= b'z') || (tk >= b'A' && tk <= b'Z') || tk == b'_' {
      pp = p;
      while (unsafe { *p } >= b'a' && unsafe { *p } <= b'z') || (unsafe { *p } >= b'A' && unsafe { *p } <= b'Z') || (unsafe { *p } >= b'0' && unsafe { *p } <= b'9') || unsafe { *p } == b'_' {
        tk = tk as i32 * 147 + unsafe { *p } as i32;
        p = unsafe { p.add(1) };
      }
      tk = (tk << 6) + (p as usize - pp as usize);// line 26
      id = sym;
      while id[Tk] != 0 {
        if tk == id[Hash] && unsafe { std::ffi::CStr::from_ptr(id[Name] as *const i8).to_string_lossy() } == unsafe { std::ffi::CStr::from_ptr(pp as *const i8).to_string_lossy() } { tk = id[Tk]; return; }
        id = id.add(Idsz);
      }
      id[Name] = pp as i32;
      id[Hash] = tk;
      tk = id[Tk] = Id;
      return;
    } else if tk >= b'0' && tk <= b'9' {
      if unsafe { *p } != 0 {
        ival = unsafe { *p } as i32 - b'0';
        while unsafe { *p } >= b'0' && unsafe { *p } <= b'9' { ival = ival * 10 + unsafe { *p } as i32 - b'0'; p = unsafe { p.add(1) }; }
      } else if unsafe { *p } == b'x' || unsafe { *p } == b'X' {
        while unsafe { *p } != 0 && ((unsafe { *p } >= b'0' && unsafe { *p } <= b'9') || (unsafe { *p } >= b'a' && unsafe { *p } <= b'f') || (unsafe { *p } >= b'A' && unsafe { *p } <= b'F')) {
          ival = ival * 16 + (unsafe { *p } as u8 & 15) + if unsafe { *p } >= b'A' { 9 } else { 0 };
          p = unsafe { p.add(1) };
        }
      } else {
        while unsafe { *p } >= b'0' && unsafe { *p } <= b'7' { ival = ival * 8 + unsafe { *p } as i32 - b'0'; p = unsafe { p.add(1) }; }
      }
      tk = Num;
      return;
    } else if tk == b'/' {
      if unsafe { *p } == b'/' {
        p = unsafe { p.add(1) };
        while unsafe { *p } != 0 && unsafe { *p } != b'\n' { p = unsafe { p.add(1) }; }
      } else {
        tk = Div;
        return;
      }
    } else if tk == b'\'' || tk == b'"' {
      pp = data;
      while unsafe { *p } != 0 && unsafe { *p } != tk {
        if (ival = unsafe { *p }) == b'\\' {
          if (ival = unsafe { *p.add(1) }) == b'n' { ival = b'\n'; }
        }
        if tk == b'"' { *data = ival; data = unsafe { data.add(1) }; }
        p = unsafe { p.add(1) };
      }
      p = unsafe { p.add(1) };
      if tk == b'"' { ival = pp as i32; } else { tk = Num; }
      return;
    } else if tk == b'=' { if unsafe { *p } == b'=' { p = unsafe { p.add(1) }; tk = Eq; } else tk = Assign; return; }
    else if tk == b'+' { if unsafe { *p } == b'+' { p = unsafe { p.add(1) }; tk = Inc; } else tk = Add; return; }
    else if tk == b'-' { if unsafe { *p } == b'-' { p = unsafe { p.add(1) }; tk = Dec; } else tk = Sub; return; }
    else if tk == b'!' { if unsafe { *p } == b'=' { p = unsafe { p.add(1) }; tk = Ne; } return; }
    else if tk == b'<' { if unsafe { *p } == b'=' { p = unsafe { p.add(1) }; tk = Le; } else if unsafe { *p } == b'<' { p = unsafe { p.add(1) }; tk = Shl; } else tk = Lt; return; }
    else if tk == b'>' { if unsafe { *p } == b'=' { p = unsafe { p.add(1) }; tk = Ge; } else if unsafe { *p } == b'>' { p = unsafe { p.add(1) }; tk = Shr; } else tk = Gt; return; }
    else if tk == b'|' { if unsafe { *p } == b'|' { p = unsafe { p.add(1) }; tk = Lor; } else tk = Or; return; }
    else if tk == b'&' { if unsafe { *p } == b'&' { p = unsafe { p.add(1) }; tk = Lan; } else tk = And; return; }
    else if tk == b'^' { tk = Xor; return; }
    else if tk == b'%' { tk = Mod; return; }
    else if tk == b'*' { tk = Mul; return; }
    else if tk == b'[' { tk = Brak; return; }
    else if tk == b'?' { tk = Cond; return; }
    else if tk == b'~' || tk == b';' || tk == b'{' || tk == b'}' || tk == b'(' || tk == b')' || tk == b']' || tk == b',' || tk == b':' { return; }
  }
}
// CHERNC_END_MARK: /data/wangjun/github/Chern-C/examples/c4/c4.c:47
"""
    rhs = """
tk = (tk << 6) + (p.load(Ordering::SeqCst) as usize - pp.load(Ordering::SeqCst) as usize);
"""
    a_lines = [line.rstrip() for line in lhs.splitlines()]
    b_lines = [line.rstrip() for line in rhs.splitlines()]
    show_result(b_lines, a_lines, 1, 2)


def example_5():
    lhs = """// CHERNC_MARK: /data/wangjun/github/Chern-C/examples/c4/c4.c:45
enum { Tk, Hash, Name, Class, Type, Val, HClass, HType, HVal, Idsz };// line 2
// CHERNC_END_MARK: /data/wangjun/github/Chern-C/examples/c4/c4.c:45



"""
    rhs = """// CHERNC_MARK: /data/wangjun/github/Chern-C/examples/c4/c4.c:45
enum TokenKind { Tk, Hash, Name, Class, Type, Val, HClass, HType, HVal, Idsz };
// CHERNC_END_MARK: /data/wangjun/github/Chern-C/examples/c4/c4.c:45"""
    a_lines = [line.rstrip() for line in lhs.splitlines()]
    b_lines = [line.rstrip() for line in rhs.splitlines()]
    show_result(a_lines, b_lines, 0, len(a_lines))

def example_6():
    lhs = """
// CHERNC_MARK: /data/wangjun/github/Chern-C/examples/bubblesort/bubblesort.c:3
fn swap(left: &mut i32, right: &mut i32) {
    let temp = *left;
    *left = *right;
    *right = temp;
}
// CHERNC_END_MARK: /data/wangjun/github/Chern-C/examples/bubblesort/bubblesort.c:3

// CHERNC_MARK: /data/wangjun/github/Chern-C/examples/bubblesort/bubblesort.c:10
fn bubble_sort(arry: &mut [i32], length: usize) {
    for i in 0..length-1 {
        for j in 0..length-i-1 {
            if arry[j] > arry[j+1] { // changed to use '>' for bubble sort
                let (left, right) = arry.split_at_mut(j + 1); // split the array into two parts
                swap(&mut left[j], &mut right[0]); // swap the elements
            }
        }
    }
}
// CHERNC_END_MARK: /data/wangjun/github/Chern-C/examples/bubblesort/bubblesort.c:10
use helloworld;
"""
    rhs = """
// CHERNC_MARK: /data/wangjun/github/Chern-C/examples/bubblesort/bubblesort.c:3
fn swap(left: &mut i32, right: &mut i32) {
    let temp = *left;
    *left = *right;
    *right = temp;
}
// CHERNC_END_MARK: /data/wangjun/github/Chern-C/examples/bubblesort/bubblesort.c:3

// CHERNC_MARK: /data/wangjun/github/Chern-C/examples/bubblesort/bubblesort.c:10
fn bubble_sort(arry: &mut [i32], length: usize) {
    for i in 0..length-1 {
        for j in 0..length-i-1 {
            if arry[j] > arry[j+1] { // changed to use '>' for bubble sort
                let (left, right) = arry.split_at_mut(j + 1); // split the array into two parts
                swap(&mut left[j], &mut right[0]); // swap the elements
            }
        }
    }
}
// CHERNC_END_MARK: /data/wangjun/github/Chern-C/examples/bubblesort/bubblesort.c:10
"""
    a_lines = [line.rstrip() for line in lhs.splitlines()]
    b_lines = [line.rstrip() for line in rhs.splitlines()]
    show_result(a_lines, b_lines, 0, len(a_lines))
   
def example_7():
    lhs = """ 
// CHERNC_MARK: /app/examples/smallprimary/alloc-testing.c:53
struct BlockHeader {
    magic_number: u32,
    bytes: usize,
}
// CHERNC_END_MARK: /app/examples/smallprimary/alloc-testing.c:56

// CHERNC_MARK: /app/examples/smallprimary/alloc-testing.c:60
static mut allocated_bytes: usize = 0;
// CHERNC_END_MARK: /app/examples/smallprimary/alloc-testing.c:60

// CHERNC_MARK: /app/examples/smallprimary/alloc-testing.c:66
static mut allocation_limit: i32 = -1;
// CHERNC_END_MARK: /app/examples/smallprimary/alloc-testing.c:66

// CHERNC_MARK: /app/examples/smallprimary/alloc-testing.c:259
fn alloc_test_get_allocated() -> usize {
    allocated_bytes
}
// CHERNC_END_MARK: /app/examples/smallprimary/alloc-testing.c:262

// CHERNC_MARK: /app/examples/smallprimary/alloc-testing.c:23
type BlockHeader = struct {
    magic_number: u32,
    bytes: usize,
};
// CHERNC_END_MARK: /app/examples/smallprimary/alloc-testing.c:23

// CHERNC_MARK: /app/examples/smallprimary/alloc-testing.c:33
const ALLOC_TEST_MAGIC: u32 = 0x72ec82d2;
// CHERNC_END_MARK: /app/examples/smallprimary/alloc-testing.c:33

// CHERNC_MARK: /app/examples/smallprimary/alloc-testing.c:254
fn alloc_test_set_limit(alloc_count: i32) {
    allocation_limit = alloc_count;
}
// CHERNC_END_MARK: /app/examples/smallprimary/alloc-testing.c:257

// CHERNC_MARK: /app/examples/smallprimary/framework.h:38
type UnitTestFunction = fn();
// CHERNC_END_MARK: /app/examples/smallprimary/framework.h:38

// CHERNC_MARK: /app/examples/smallprimary/alloc-testing.c:70
fn alloc_test_get_header(ptr: *const u8) -> *const BlockHeader {
    let result = unsafe { (ptr as *const BlockHeader).offset(-1) };
    assert_eq!(result.magic_number, ALLOC_TEST_MAGIC);
    result
}
// CHERNC_END_MARK: /app/examples/smallprimary/alloc-testing.c:81

// CHERNC_MARK: /app/examples/smallprimary/alloc-testing.c:44
const FREE_PATTERN: u32 = 0xDEADBEEF;
// CHERNC_END_MARK: /app/examples/smallprimary/alloc-testing.c:44

// CHERNC_MARK: /app/examples/smallprimary/alloc-testing.c:39
const MALLOC_PATTERN: u32 = 0xBAADF00D;
// CHERNC_END_MARK: /app/examples/smallprimary/alloc-testing.c:39

// CHERNC_MARK: /app/examples/smallprimary/framework.c:31
fn run_test(test: UnitTestFunction) {
    // Turn off any allocation limits that may have been set
    // by a previous test.
    alloc_test_set_limit(-1);

    // Run the test
    test();

    // Check that all memory was correctly freed back during
    // the test.
    assert_eq!(alloc_test_get_allocated(), 0);
}
// CHERNC_END_MARK: /app/examples/smallprimary/framework.c:46

// CHERNC_MARK: /app/examples/smallprimary/alloc-testing.c:85
fn alloc_test_overwrite(ptr: *mut u8, length: usize, pattern: u32) {
    let mut byte_ptr = ptr;
    for i in 0..length {
        let pattern_seq = (i & 3) as i32;
        let b = ((pattern >> (8 * pattern_seq)) & 0xff) as u8;
        unsafe { *byte_ptr.add(i) = b };
    }
}
// CHERNC_END_MARK: /app/examples/smallprimary/alloc-testing.c:100

// CHERNC_MARK: /app/examples/smallprimary/alloc-testing.c:150
fn alloc_test_free(ptr: *mut u8) {
    let header = alloc_test_get_header(ptr);
    let block_size = header.bytes;
    assert!(allocated_bytes >= block_size);

    // Trash the allocated block to foil any code that relies on memory
    // that has been freed.
    alloc_test_overwrite(ptr, header.bytes, FREE_PATTERN);

    // Trash the magic number in the block header to stop the same block
    // from being freed again.
    unsafe { (*header).magic_number = 0 };

    // Free the allocated memory.
    unsafe { free(header as *mut std::ffi::c_void) };

    // Update counter
    allocated_bytes -= block_size;
}
// CHERNC_END_MARK: /app/examples/smallprimary/alloc-testing.c:184

// CHERNC_MARK: /app/examples/smallprimary/alloc-testing.c:104
fn alloc_test_malloc(bytes: usize) -> *mut u8 {
    let header = unsafe { malloc(std::mem::size_of::<BlockHeader>() + bytes) as *mut BlockHeader };
    if header.is_null() {
        return std::ptr::null_mut();
    }

    unsafe { (*header).magic_number = ALLOC_TEST_MAGIC };
    unsafe { (*header).bytes = bytes };

    // Fill memory with MALLOC_PATTERN, to ensure that code under test
    // does not rely on memory being initialised to zero.
    let ptr = unsafe { header.add(1) };
    alloc_test_overwrite(ptr, bytes, MALLOC_PATTERN);

    // Update counter
    allocated_bytes += bytes;

    // Decrease the allocation limit
    if allocation_limit > 0 {
        allocation_limit -= 1;
    }

    // Skip past the header and return the block itself
    unsafe { header.add(1) }
}
// CHERNC_END_MARK: /app/examples/smallprimary/alloc-testing.c:146

// CHERNC_MARK: /app/examples/smallprimary/framework.c:48
fn run_tests(tests: &[fn()]) {
    for test in tests.iter().filter(|&&test| !test.is_null()) {
        run_test(test);
    }
}
// CHERNC_END_MARK: /app/examples/smallprimary/framework.c:55

// CHERNC_MARK: /app/examples/smallprimary/alloc-testing.c:219
fn alloc_test_calloc(nmemb: usize, bytes: usize) -> *mut u8 {
    let total_bytes = nmemb * bytes;
    let result = alloc_test_malloc(total_bytes);
    if result.is_null() {
        return std::ptr::null_mut();
    }
    unsafe { memset(result, 0, total_bytes) };
    result
}
// CHERNC_END_MARK: /app/examples/smallprimary/alloc-testing.c:237

// CHERNC_MARK: /app/examples/smallprimary/alloc-testing.c:239
fn alloc_test_strdup(string: &str) -> *mut u8 {
    let result = alloc_test_malloc(string.len() + 1);
    if result.is_null() {
        return std::ptr::null_mut();
    }
    unsafe { strcpy(result, string.as_ptr()) };
    result
}
// CHERNC_END_MARK: /app/examples/smallprimary/alloc-testing.c:252

// CHERNC_MARK: /app/examples/smallprimary/alloc-testing.c:186
fn alloc_test_realloc(ptr: *mut u8, bytes: usize) -> *mut u8 {
    let new_ptr = alloc_test_malloc(bytes);
    if new_ptr.is_null() {
        return std::ptr::null_mut();
    }

    if !ptr.is_null() {
        let header = alloc_test_get_header(ptr);
        let bytes_to_copy = header.bytes;
        if bytes_to_copy > bytes {
            bytes_to_copy = bytes;
        }
        unsafe { memcpy(new_ptr, ptr, bytes_to_copy) };
        alloc_test_free(ptr);
    }

    new_ptr
}
// CHERNC_END_MARK: /app/examples/smallprimary/alloc-testing.c:217
"""
    rhs = """
// CHERNC_MARK: /app/examples/smallprimary/alloc-testing.c:23
type BlockHeader = struct {
    magic_number: u32,
    bytes: usize,
};
// CHERNC_END_MARK: /app/examples/smallprimary/alloc-testing.c:23
"""

    a_lines = [line.rstrip() for line in lhs.splitlines()]
    b_lines = [line.rstrip() for line in rhs.splitlines()]
    show_result(b_lines, a_lines, 0, len(a_lines))

def example_8():
    lhs = """
// CHERNC_MARK: /app/examples/smallprimary/alloc-testing.c:66
static mut allocation_limit: AtomicI32 = AtomicI32::new(-1);
// CHERNC_END_MARK: /app/examples/smallprimary/alloc-testing.c:66

// CHERNC_MARK: /app/examples/smallprimary/alloc-testing.c:53
#[repr(C)]
struct BlockHeader {
    magic_number: u32,
    bytes: usize,
}
// CHERNC_END_MARK: /app/examples/smallprimary/alloc-testing.c:56

// CHERNC_MARK: /app/examples/smallprimary/alloc-testing.c:60
static mut allocated_bytes: usize = 0;
// CHERNC_END_MARK: /app/examples/smallprimary/alloc-testing.c:60

// CHERNC_MARK: /app/examples/smallprimary/alloc-testing.c:51
type BlockHeader = self::BlockHeader;
// CHERNC_END_MARK: /app/examples/smallprimary/alloc-testing.c:51

// CHERNC_MARK: /app/examples/smallprimary/framework.h:38
type UnitTestFunction = fn();
// CHERNC_END_MARK: /app/examples/smallprimary/framework.h:38

// CHERNC_MARK: /app/examples/smallprimary/alloc-testing.c:254
fn alloc_test_set_limit(alloc_count: i32) {
    allocation_limit.store(alloc_count, Ordering::SeqCst);
}
// CHERNC_END_MARK: /app/examples/smallprimary/alloc-testing.c:257

// CHERNC_MARK: /app/examples/smallprimary/alloc-testing.c:33
const ALLOC_TEST_MAGIC: u32 = 0x72ec82d2;
// CHERNC_END_MARK: /app/examples/smallprimary/alloc-testing.c:33

// CHERNC_MARK: /app/examples/smallprimary/alloc-testing.c:259
fn alloc_test_get_allocated() -> usize {
    unsafe { allocated_bytes }
}
// CHERNC_END_MARK: /app/examples/smallprimary/alloc-testing.c:262

// CHERNC_MARK: /app/examples/smallprimary/alloc-testing.c:39
const MALLOC_PATTERN: u32 = 0xBAADF00D;
// CHERNC_END_MARK: /app/examples/smallprimary/alloc-testing.c:39

// CHERNC_MARK: /app/examples/smallprimary/alloc-testing.c:70
fn alloc_test_get_header(ptr: *mut u8) -> *mut BlockHeader {
    let result = (ptr as *mut BlockHeader).offset(-1);
    assert!(unsafe { (*result).magic_number == ALLOC_TEST_MAGIC });
    result
}
// CHERNC_END_MARK: /app/examples/smallprimary/alloc-testing.c:81

// CHERNC_MARK: /app/examples/smallprimary/framework.c:31
fn run_test(test: UnitTestFunction) {
    // Turn off any allocation limits that may have been set
    // by a previous test.
    allocation_limit.store(-1, Ordering::SeqCst);

    // Run the test
    test();

    // Check that all memory was correctly freed back during
    // the test.
    assert_eq!(alloc_test_get_allocated(), 0);
}
// CHERNC_END_MARK: /app/examples/smallprimary/framework.c:46

// CHERNC_MARK: /app/examples/smallprimary/alloc-testing.c:85
fn alloc_test_overwrite(ptr: *mut u8, length: usize, pattern: u32) {
    let byte_ptr = ptr;
    for i in 0..length {
        let pattern_seq = (i & 3) as usize;
        let b = ((pattern >> (8 * pattern_seq)) & 0xff) as u8;
        unsafe { byte_ptr.add(i).write(b) };
    }
}
// CHERNC_END_MARK: /app/examples/smallprimary/alloc-testing.c:100

// CHERNC_MARK: /app/examples/smallprimary/alloc-testing.c:44
const FREE_PATTERN: u32 = 0xDEADBEEF;
// CHERNC_END_MARK: /app/examples/smallprimary/alloc-testing.c:44

// CHERNC_MARK: /app/examples/smallprimary/framework.c:48
fn run_tests(tests: &[UnitTestFunction]) {
    for test in tests {
        if test.is_null() {
            break;
        }
        run_test(*test);
    }
}
// CHERNC_END_MARK: /app/examples/smallprimary/framework.c:55

// CHERNC_MARK: /app/examples/smallprimary/alloc-testing.c:150
fn alloc_test_free(ptr: *mut u8) {
    if ptr.is_null() {
        return;
    }

    let header = alloc_test_get_header(ptr);
    let block_size = unsafe { (*header).bytes };
    assert!(unsafe { allocated_bytes } >= block_size);

    alloc_test_overwrite(ptr, block_size, FREE_PATTERN);
    unsafe { (*header).magic_number = 0 };
    free(header as *mut c_void);
    unsafe { allocated_bytes -= block_size };
}
// CHERNC_END_MARK: /app/examples/smallprimary/alloc-testing.c:184

// CHERNC_MARK: /app/examples/smallprimary/alloc-testing.c:104
fn alloc_test_malloc(bytes: usize) -> *mut u8 {
    if allocation_limit.load(Ordering::SeqCst) == 0 {
        return ptr::null_mut();
    }

    let header = malloc(bytes + std::mem::size_of::<BlockHeader>()) as *mut BlockHeader;
    if header.is_null() {
        return ptr::null_mut();
    }

    unsafe {
        (*header).magic_number = ALLOC_TEST_MAGIC;
        (*header).bytes = bytes;
        alloc_test_overwrite((header as *mut u8).add(std::mem::size_of::<BlockHeader>()), bytes, MALLOC_PATTERN);
        allocated_bytes += bytes;
        if allocation_limit.load(Ordering::SeqCst) > 0 {
            allocation_limit.fetch_sub(1, Ordering::SeqCst);
        }
    }
    (header as *mut u8).add(std::mem::size_of::<BlockHeader>())
}
// CHERNC_END_MARK: /app/examples/smallprimary/alloc-testing.c:146

// CHERNC_MARK: /app/examples/smallprimary/alloc-testing.c:186
use std::sync::atomic::{AtomicI32, Ordering};
use std::ptr::{self, null_mut};
use std::ffi::c_void;
use std::mem;

#[repr(C)]
struct BlockHeader {
    magic_number: u32,
    bytes: usize,
}

static mut allocated_bytes: usize = 0;
static mut allocation_limit: AtomicI32 = AtomicI32::new(-1);

fn alloc_test_get_header(ptr: *mut u8) -> *mut BlockHeader {
    let result = (ptr as *mut BlockHeader).offset(-1);
    assert!(unsafe { (*result).magic_number == ALLOC_TEST_MAGIC });
    result
}

fn alloc_test_overwrite(ptr: *mut u8, length: usize, pattern: u32) {
    let byte_ptr = ptr;
    for i in 0..length {
        let pattern_seq = (i & 3) as usize;
        let b = ((pattern >> (8 * pattern_seq)) & 0xff) as u8;
        unsafe { byte_ptr.add(i).write(b) };
    }
}

fn alloc_test_free(ptr: *mut u8) {
    if ptr.is_null() {
        return;
    }

    let header = alloc_test_get_header(ptr);
    let block_size = unsafe { (*header).bytes };
    assert!(unsafe { allocated_bytes } >= block_size);

    alloc_test_overwrite(ptr, block_size, FREE_PATTERN);
    unsafe { (*header).magic_number = 0 };
    free(header as *mut c_void);
    unsafe { allocated_bytes -= block_size };
}

fn alloc_test_malloc(bytes: usize) -> *mut u8 {
    if allocation_limit.load(Ordering::SeqCst) == 0 {
        return null_mut();
    }

    let header = malloc(bytes + mem::size_of::<BlockHeader>()) as *mut BlockHeader;
    if header.is_null() {
        return null_mut();
    }

    unsafe {
        (*header).magic_number = ALLOC_TEST_MAGIC;
        (*header).bytes = bytes;
        alloc_test_overwrite((header as *mut u8).add(mem::size_of::<BlockHeader>()), bytes, MALLOC_PATTERN);
        allocated_bytes += bytes;
        if allocation_limit.load(Ordering::SeqCst) > 0 {
            allocation_limit.fetch_sub(1, Ordering::SeqCst);
        }
    }
    (header as *mut u8).add(mem::size_of::<BlockHeader>())
}

fn alloc_test_calloc(nmemb: usize, bytes: usize) -> *mut u8 {
    let total_bytes = nmemb.checked_mul(bytes).expect("Overflow");
    let result = alloc_test_malloc(total_bytes);
    if result.is_null() {
        return null_mut();
    }
    unsafe { ptr::write_bytes(result, 0, total_bytes) };
    result
}

fn alloc_test_strdup(string: &str) -> *mut u8 {
    let result = alloc_test_malloc(string.len() + 1);
    if result.is_null() {
        return null_mut();
    }
    unsafe { ptr::copy(string.as_ptr(), result, string.len()) };
    unsafe { *result.add(string.len()) = 0 };
    result
}

fn alloc_test_realloc(ptr: *mut u8, bytes: usize) -> *mut u8 {
    BlockHeader *header;
    void *new_ptr;
    size_t bytes_to_copy;

    /* Allocate the new block */

    new_ptr = alloc_test_malloc(bytes);

    if new_ptr == null_mut() {
        return null_mut();
    }

    /* Copy over the old data and free the old block, if there was any. */

    if ptr != null_mut() {
        header = alloc_test_get_header(ptr);

        bytes_to_copy = header->bytes;

        if bytes_to_copy > bytes {
            bytes_to_copy = bytes;
        }

        memcpy(new_ptr, ptr, bytes_to_copy);

        alloc_test_free(ptr);
    }

    return new_ptr;
}
// CHERNC_END_MARK: /app/examples/smallprimary/alloc-testing.c:217

// CHERNC_MARK: /app/examples/smallprimary/alloc-testing.c:239
fn alloc_test_strdup(string: &str) -> *mut u8 {
    let result = alloc_test_malloc(string.len() + 1);
    if result.is_null() {
        return ptr::null_mut();
    }
    unsafe { ptr::copy(string.as_ptr(), result, string.len()) };
    unsafe { *result.add(string.len()) = 0 };
    result
}
// CHERNC_END_MARK: /app/examples/smallprimary/alloc-testing.c:252

// CHERNC_MARK: /app/examples/smallprimary/alloc-testing.c:219
fn alloc_test_calloc(nmemb: usize, bytes: usize) -> *mut u8 {
    let total_bytes = nmemb.checked_mul(bytes).expect("Overflow");
    let result = alloc_test_malloc(total_bytes);
    if result.is_null() {
        return ptr::null_mut();
    }
    unsafe { ptr::write_bytes(result, 0, total_bytes) };
    result
}
// CHERNC_END_MARK: /app/examples/smallprimary/alloc-testing.c:237
"""
    rhs = """
fn alloc_test_realloc(ptr: *mut u8, bytes: usize) -> *mut u8 {
    let header: *mut BlockHeader = if ptr.is_null() {
        null_mut()
    } else {
        alloc_test_get_header(ptr)
    };

    let new_ptr = alloc_test_malloc(bytes);

    if new_ptr.is_null() {
        return null_mut();
    }

    if !ptr.is_null() {
        let bytes_to_copy = unsafe { (*header).bytes };

        if bytes_to_copy > bytes {
            bytes_to_copy = bytes;
        }

        unsafe { ptr::copy(ptr, new_ptr, bytes_to_copy) };

        alloc_test_free(ptr);
    }

    new_ptr
}
"""

    a_lines = [line.rstrip() for line in lhs.splitlines()]
    b_lines = [line.rstrip() for line in rhs.splitlines()]
    show_result(b_lines, a_lines, 0, len(a_lines))

def example_9():
    lhs = """
// CHERNC_MARK: /data/wangjun/github/Chern-C/examples/smallprimary/alloc-testing.c:66
static mut allocation_limit: i32 = -1;
// CHERNC_END_MARK: /data/wangjun/github/Chern-C/examples/smallprimary/alloc-testing.c:66

// CHERNC_MARK: /data/wangjun/github/Chern-C/examples/smallprimary/framework.c:48
fn run_tests(tests: &[UnitTestFunction]) {
    for test in tests.iter().take_while(|&&test| test != None) {
        run_test(test);// line 113
    }
}
// CHERNC_END_MARK: /data/wangjun/github/Chern-C/examples/smallprimary/framework.c:55

// CHERNC_MARK: /data/wangjun/github/Chern-C/examples/smallprimary/framework.c:48
fn run_tests(tests: &[UnitTestFunction]) {
    for test in tests.iter().take_while(|&&test| test != None) {
        run_test(*test); // Dereference the borrow
    }
}
// CHERNC_END_MARK: /data/wangjun/github/Chern-C/examples/smallprimary/framework.c:55

// CHERNC_MARK: /data/wangjun/github/Chern-C/examples/smallprimary/alloc-testing.c:186
fn alloc_test_realloc(ptr: *mut u8, bytes: usize) -> *mut u8 {
    let new_ptr = alloc_test_malloc(bytes);

    if new_ptr.is_null() {
        return std::ptr::null_mut();
    }

    if !ptr.is_null() {
        let header = alloc_test_get_header(ptr);
        let mut bytes_to_copy = unsafe { (*header).bytes }; // Make this binding mutable

        if bytes_to_copy > bytes {
            bytes_to_copy = bytes;
        }

        unsafe {
            std::ptr::copy(ptr, new_ptr, bytes_to_copy);
        }

        alloc_test_free(ptr);
    }

    new_ptr
}
// CHERNC_END_MARK: /data/wangjun/github/Chern-C/examples/smallprimary/alloc-testing.c:217
"""
    rhs = """
// CHERNC_MARK: /data/wangjun/github/Chern-C/examples/smallprimary/framework.c:48
fn run_tests(tests: &[UnitTestFunction]) {
    for test in tests.iter().take_while(|&&test| test != None) {
        run_test(*test); // Dereference the borrow
    }
}
// CHERNC_END_MARK: /data/wangjun/github/Chern-C/examples/smallprimary/framework.c:55
"""
    a_lines = [line.rstrip() for line in lhs.splitlines()]
    b_lines = [line.rstrip() for line in rhs.splitlines()]
    show_result(b_lines, a_lines, 0, len(a_lines))

if __name__ == "__main__":
    # example_1()
    # example_2()
    # example_3()
    # example_4()
    # example_5()
    # example_6()
    # example_7()
    # example_8()
    example_9()